﻿using Refit;

namespace WaferService
{
    public class EFEMConfig
    {
        public int LoadPort { get; init; } = 2;

        public required string Host { get; init; }

        public double AlignerAngle { get; init; } = 45;

        public required int Port { get; init; }
    }


    public interface IEFEMService : IDisposable
    {
        string GetAddress();

        IAsyncEnumerable<string> GetEvents(CancellationToken tok);

        Task<bool> Connect(CancellationToken tok = default);

        Task Initialize(CancellationToken tok = default);

        Task Open(string loadPort, CancellationToken tok = default);

        Task Close(string loadPort, CancellationToken tok = default);

        Task<string> GetWaferMapping(string loadPort, CancellationToken tok = default);

        Task Load(string pos, string arm, CancellationToken tok = default);

        Task UnLoad(string pos, string arm, CancellationToken tok = default);

        Task Change(string pos, string loading, string unloading, CancellationToken tok = default);

        Task Align(string angle, CancellationToken tok = default);

        Task<LoadPortStatus> GetLoadPortStatus(int n, CancellationToken tok = default);

        Task<string> GetCarrierID(string loadPort, CancellationToken tok = default);
    }


    public class LoadPortStatus
    {
        public bool Placement { get; internal set; }

        public bool Presence { get; internal set; }

        public bool AccessSW { get; internal set; }

        public bool Clamp { get; internal set; }

        public bool Dock { get; internal set; }

        public bool Door { get; internal set; }

        public bool Latch { get; internal set; }
    }


    public static class Parameter
    {
        public static string All() => "ALL";
        public static string Robot() => "ROB";
        public static string LoadPort(int n) => "P" + n;
        public static string LoadPort(string n) => "P" + n;
        public static string Aligner() => "ALIGN1";
        public static string LoadPort(int n, int slot)
        {
            string xx = slot.ToString();
            if (xx.Length == 1)
            {
                xx = "0" + xx;
            }
            return "P" + n + xx;
        }
        public static string LoadLock() => "LLA";
        public static string Arm(int i) => "ARM" + i.ToString();
        public static string Arm(string i) => "ARM" + i;
        public static string Angle(double degree) => "A" + string.Format("{0:.00}", degree);
    }

    public interface IMotionControlService
    {
        Task<bool> Connect();

        Task MotionFeedForward(bool status, CancellationToken tok = default);

        Task<bool> GetMotionFeedForward(CancellationToken tok = default);

        Task<int> GetMotionStatus(CancellationToken tok = default);

        Task MotorCommut(int axis, CancellationToken tok = default);
        Task MotorCommutationMode(int mode, CancellationToken tok = default);

        /// <summary>
        /// 到Loading位置
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task GoToLoadingPos(CancellationToken tok = default);

        /// <summary>
        /// 到Ready(安全)位置
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task GoToReadyPos(CancellationToken tok = default);

        /// <summary>
        /// 判断是否在loading位置
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> IsInLoadingPos(CancellationToken tok = default);

        Task SwitchToLaserPosition(CancellationToken tok = default);


        Task SwitchToEncoderPosition(CancellationToken tok = default);

        /// <summary>
        /// 获取双轴是否全部定位完成
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> GetLocFinished(CancellationToken tok = default);
        /// <summary>
        /// 获取双轴FeedBackPosition
        /// </summary>
        /// <param name="tok"></param>
        /// <returns>double[2]:  double[0]:XEncoderPos;double[1]:YEncoderPos</returns>
        Task<double[]> GetFeedBackPosition(CancellationToken tok = default);

        /// <summary>
        /// 获取双轴ReferencePosition
        /// </summary>
        /// <param name="tok"></param>
        /// <returns>double[2]:  double[0]:XEncoderPos;double[1]:YEncoderPos</returns>
        Task<double[]> GetReferencePosition(CancellationToken tok = default);

        /// <summary>
        /// 设置双轴运动速度
        /// </summary>
        /// <param name="velocity"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetVelocityImm(double velocity, CancellationToken tok = default);

        /// <summary>
        /// 设置双轴加速度
        /// </summary>
        /// <param name="accel"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetAccelerationImm(double accel, CancellationToken tok = default);

        /// <summary>
        /// 设置双轴减速度
        /// </summary>
        /// <param name="deceleration"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetDecelerationImm(double deceleration, CancellationToken tok = default);

        /// <summary>
        /// 设置双轴绝对位置
        /// </summary>
        /// <param name="posx"></param>
        /// <param name="posy"></param>
        /// <param name="flag"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetAbsolutePosition(double posx, double posy, bool flag, CancellationToken tok = default);

        /// <summary>
        /// 设置双轴绝对位置//包含LiffterPin互锁
        /// </summary>
        /// <param name="posx"></param>
        /// <param name="posy"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetAbsolutePosition(double posx, double posy, CancellationToken tok = default);

        /// <summary>
        /// 设置双轴相对位置
        /// </summary>
        /// <param name="posx"></param>
        /// <param name="posy"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetRelativePosition(double posx, double posy, CancellationToken tok = default);

        /// <summary>
        /// HOME
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task Home(CancellationToken tok = default);

        /// <summary>
        /// 设置软限位位置
        /// </summary>
        /// <param name="softLimit">软限位位置</param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetSoftLimit(double softLimit, CancellationToken tok = default);

        /// <summary>
        /// 设置软限位使能
        /// </summary>
        /// <param name="softLimit">软限位位置</param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetSoftLimitEnable(bool isenable, CancellationToken tok = default);

        /// <summary>
        /// 读取特定值
        /// </summary>
        /// <param name="cmd">命令字符串</param>
        /// <param name="axisID">轴ID</param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<object> GetVariable(string cmd, int axisID, CancellationToken tok = default);

        /// <summary>
        /// 循环测试
        /// </summary>
        /// <param name="cmd">rectangle\round\random\stop</param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task CyclingTest(string cmd, CancellationToken tok = default);

        /// <summary>
        /// 移动faradaycup到SEM中心
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task MoveFaradayCupToSEMCenter(CancellationToken tok = default);

        /// <summary>
        ///  判断坐标传感器，返回true为Laser，返回false为Encoder
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> GetServoMode(CancellationToken tok = default);


        SamplePositionConfig GetSamplePositionConfig();

        Task<string> Transaction(string transaction, CancellationToken tok = default);

        //Get Motor State
        Task<MotorStates> Get_MotorState(int axisId, CancellationToken tok = default);

        //Get Velocity
        Task<double> Get_Velocity(int axisId, CancellationToken tok = default);

        //Get Feedback Velocity
        Task<double> Get_FeedbackVelocity(int axisId, CancellationToken tok = default);

        //Get Acceleration
        Task<double> Get_Acceleration(int axisId, CancellationToken tok = default);

        //Get Deceleration
        Task<double> Get_Deceleration(int axisId, CancellationToken tok = default);

        //Get KillDeceleration
        Task<double> Get_KillDeceleration(int axisId, CancellationToken tok = default);

        //Get Program State////State:Complied,Runing,Suspended,Autoroutine is running
        Task<string> Get_ProgramStates(int iBufferId, CancellationToken tok = default);

        //Get reference position
        Task<double> Get_ReferencePosition(int axisId, CancellationToken tok = default);

        //Get encoder value/Feedback Position
        Task<double> Get_FeedbackPosition(int axisId, CancellationToken tok = default);

        //Get Position Error
        Task<double> Get_PositionError(int axisId, CancellationToken tok = default);

        //Get Hardware limits state
        Task<object> Get_HardwareLimitState(CancellationToken tok = default);

        //Get Digital Input/Output
        Task<int> Get_DigitalInput(CancellationToken tok = default);
        Task<int> Get_DigitalOutput(CancellationToken tok = default);

        //Get Jerk//急停
        Task<double> Get_Jerk(int axisId, CancellationToken tok = default);

        //Communication Open/Close
        Task Open(bool isSimulator, CancellationToken tok = default);
        Task Close(CancellationToken tok = default);

        //Move to absolute position
        Task Set_MotorMoveToAbsolutePosition(int axisId, double pos, CancellationToken tok = default);

        //Move to relative position
        Task Set_MotorMoveToRelativePosition(int axisId, double pos, CancellationToken tok = default);

        //Motor Enable/Disable
        Task Set_MotorEnable(int axisId, CancellationToken tok = default);
        Task Set_MotorDisable(int axisId, CancellationToken tok = default);
        Task Set_MotorDisableAll(CancellationToken tok = default);

        //Stop Motion/Halt Command
        Task Set_MotorHalt(int axisId, CancellationToken tok = default);
        Task Set_MotorHaltAll(CancellationToken tok = default);

        //Jog Command
        Task Set_JogStart(int axisId, double vel, CancellationToken tok = default);
        Task Set_JogStop(int axisId, CancellationToken tok = default);

        //On and Off General Output
        Task Set_GeneralOutput(CancellationToken tok = default);

        //Set Velocity
        Task Set_Velocity(int axisId, double value, CancellationToken tok = default);

        //Set Acceleration
        Task Set_Acceleration(int axisId, double value, CancellationToken tok = default);

        //Set Deceleration
        Task Set_Deceleration(int axisId, double value, CancellationToken tok = default);

        //Set KillDeceleration
        Task Set_KillDeceleration(int axisId, double value, CancellationToken tok = default);

        //Set Jerk//急停
        Task Set_Jerk(int axisId, double value, CancellationToken tok = default);
    }

    public record class SamplePositionConfig
    {
        public double FaradayCupSEMX { set; get; }
        public double FaradayCupSEMY { set; get; }
        public double FaradayCupLOWX { set; get; }
        public double FaradayCupLOWY { set; get; }

        public double SnLOWX { set; get; }
        public double SnLOWY { set; get; }
        public double SiLOWX { set; get; }
        public double SiLOWY { set; get; }
        public double CuLOWX { set; get; }
        public double CuLOWY { set; get; }
        public double AuLOWX { set; get; }
        public double AuLOWY { set; get; }
    }

    [Flags]
    public enum MotorStates
    {
        ACSC_ALL = -1,
        ACSC_NONE = 0,
        ACSC_MST_ENABLE = 1,
        ACSC_MST_INPOS = 16,
        ACSC_MST_MOVE = 32,
        ACSC_MST_ACC = 64
    }

    public class Jacking
    {
        public static List<DataItem> JackInfo = new List<DataItem>()
    {
        DataItem.FromAddress("DB3.DBX0.0"),
        DataItem.FromAddress("DB3.DBX22.0"),
        DataItem.FromAddress("DB3.DBX22.1"),
        DataItem.FromAddress("DB3.DBX22.2"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=24 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=160 },
        DataItem.FromAddress("DB3.DBX28.0"),
        DataItem.FromAddress("DB3.DBX28.1"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Word,DB=3,StartByteAdr=30 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=2 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=4 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=19,StartByteAdr=6 },
    };
        public static List<DataItem> JackParams = new List<DataItem>()
    {
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=282 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=286 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=294 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=290 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=342 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=346 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=350 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=354 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=270 },
        //DataItem.FromAddress("DB3.DBD206"),
        //DataItem.FromAddress("DB3.DBD210"),
        //DataItem.FromAddress("DB3.DBD214"),
        //DataItem.FromAddress("DB3.DBD218"),
        //DataItem.FromAddress("DB3.DBD254"),
        //DataItem.FromAddress("DB3.DBD258"),
        //DataItem.FromAddress("DB3.DBD262"),
        //DataItem.FromAddress("DB3.DBD266"),
        //DataItem.FromAddress("DB3.DBD270"),
    };
        #region 顶升伺服
        //读
        public const string Get_Enable = "DB3.DBX0.0";//使能
        public const string Get_Ready = "DB3.DBX22.0";//顶升伺服就绪
        public const string Get_Alarm = "DB3.DBX22.1";//故障
        public const string Get_LocationFinish = "DB3.DBX22.2";//定位完成
        public const string Get_CurrentPosition = "DB3.DBR24";//当前位置
        public const string Get_CurrentSpeed = "DB3.DBR386";//当前速度
        public const string Get_HomeFinish = "DB3.DBX28.0";//原点完成
        public const string Get_Running = "DB3.DBX28.1";//运行中
        public const string Get_AlarmID = "DB3.DBT30";//故障ID
        public const string Get_HomeSensorStatus = "I0.0";//原点位/下位
        public const string Get_TopLimitSensorStatus = "I0.1";//上极限位
        public const string Get_BottomLimitSensorStatus = "I0.2";//下极限位
        public const string Get_TopSensorStatus = "I2.0";//上位
        public const string Get_MiddleSensorStatus = "I2.1";//中位
        public const string Get_DetectionSensor1Status = "I2.2";//晶圆检测传感器1
        public const string Get_DetectionSensor2Status = "I2.3";//晶圆检测传感器2
        public const string Get_DetectionSensor3Status = "I2.4";//晶圆检测传感器3
        public const string Get_AutoStep = "DB8.DBI2";
        public const string Get_PauseStep = "DB8.DBI4";
        public const string Get_WaferPos = "DB19.DBI6";//晶圆位置

        //写
        public const string Set_Enable = "DB3.DBX0.0";//使能
        public const string Set_JogUp = "DB3.DBX0.1";//正转点动
        public const string Set_JogDown = "DB3.DBX0.2";//反转点动
        public const string Set_BackHome = "DB3.DBX0.3";//回原点
        public const string Set_LocationStart = "DB3.DBX1.2";//定位启动
        public const string Set_AlarmClear = "DB3.DBX1.0";//故障复位
        public const string Set_Speed = "DB3.DBD2";//速度设定
        public const string Set_Position = "DB3.DBD10";//位置设定
        public const string Set_InitSpeed = "DB19.DBD270";//初始速度
        public const string Set_BottomPosition = "DB19.DBD282";//下位
        public const string Set_MiddlePosition = "DB19.DBD286";//中位
        public const string Set_TouchPosition = "DB19.DBD290";//减速位
        public const string Set_TopPosition = "DB19.DBD294";//上位
        public const string Set_Speed1 = "DB19.DBD342";//速度1
        public const string Set_Speed2 = "DB19.DBD346";//速度2
        public const string Set_Speed3 = "DB19.DBD350";//速度3
        public const string Set_Speed4 = "DB19.DBD354";//速度4
        public const string Set_Speed5 = "DB3.DBD270";//速度5
        public const string Set_Jerk = "DB3.DBX1.1";//急停

        public const string Set_GoBottomPosition = "DB16.DBX0.0";
        public const string Set_GoMiddlePosition = "DB16.DBX0.2";
        public const string Set_GoTouchPosition = "DB16.DBX0.4";
        public const string Set_GoTopPosition = "DB16.DBX0.6";
        #endregion
    }

    public class Spin
    {
        public static List<DataItem> SpinInfo = new List<DataItem>()
    {
        DataItem.FromAddress("DB3.DBX32.0"),
        DataItem.FromAddress("DB3.DBX54.0"),
        DataItem.FromAddress("DB3.DBX54.1"),
        DataItem.FromAddress("DB3.DBX54.2"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=56 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=164 },
        DataItem.FromAddress("DB3.DBX60.0"),
        DataItem.FromAddress("DB3.DBX60.1"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.DInt,DB=3,StartByteAdr=62 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=10 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=12 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=19,StartByteAdr=8 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=19,StartByteAdr=10 },
    };
        public static List<DataItem> SpinParams = new List<DataItem>()
    {
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=298 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=302 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=306 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=310 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=314 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=318 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=322 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=326 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=274 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB= 19,StartByteAdr=0 },
        //DataItem.FromAddress("DB3.DBD222"),
        //DataItem.FromAddress("DB3.DBD226"),
        //DataItem.FromAddress("DB3.DBD230"),
        //DataItem.FromAddress("DB3.DBD234"),
        //DataItem.FromAddress("DB3.DBD284"),
        //DataItem.FromAddress("DB3.DBD288"),
        //DataItem.FromAddress("DB3.DBD238"),
    };

        #region 旋转伺服
        //读
        public const string Get_Enable = "DB3.DBX32.0";//使能
        public const string Get_Ready = "DB3.DBX54.0";//顶升伺服就绪
        public const string Get_Alarm = "DB3.DBX54.1";//故障
        public const string Get_LocationFinish = "DB3.DBX54.2";//定位完成
        public const string Get_CurrentPosition = "DB3.DBR56";//当前位置
        public const string Get_CurrentSpeed = "DB3.DBR390";//当前速度
        public const string Get_HomeFinish = "DB3.DBX60.0";//原点完成
        public const string Get_Operating = "DB3.DBX60.1";//运行中
        public const string Get_AlarmID = "DB3.DBT62";//故障ID
        public const string Get_HomeSensorStatus = "I0.3";//原点位
        public const string Get_DetectionSensor1Status = "I0.4";//检测位1
        public const string Get_DetectionSensor2Status = "I0.5";//检测位2
        public const string Get_AutoStep = "DB8.DBI10";
        public const string Get_PauseStep = "DB8.DBI12";
        public const string Get_WaferPos1 = "DB19.DBI8";//晶圆位置
        public const string Get_WaferPos2 = "DB19.DBI10";//晶圆位置

        //写
        public const string Set_Enable = "DB3.DBX32.0";//使能
        public const string Set_Forward = "DB3.DBX32.1";//正转点动
        public const string Set_Reversal = "DB3.DBX32.2";//反转点动
        public const string Set_BackHome = "DB3.DBX32.3";//回原点
        public const string Set_LocationStart = "DB3.DBX33.2";//定位启动
        public const string Set_AlarmClear = "DB3.DBX33.0";//故障复位
        public const string Set_Speed = "DB3.DBD34";//速度设定
        public const string Set_Position = "DB3.DBD42";//位置设定
        public const string Set_InitSpeed = "DB19.DBD274";//初始速度
        public const string Set_ReadyPosition = "DB19.DBD298";//待机位
        public const string Set_ReceivePosition = "DB19.DBD302";//接晶圆位
        public const string Set_SendPosition = "DB19.DBD306";//送晶圆位
        public const string Set_AvoidPosition = "DB19.DBD310";//避让位
        public const string Set_SendPosition2 = "DB19.DBD314";//第二次送晶圆位
        public const string Set_AvoidPosition2 = "DB19.DBD318";//第二次避让位
        public const string Set_CorrectErrorPosition = "DB19.DBD322";//纠偏位置
        public const string Set_AutoSpeed = "DB19.DBD326";//自动速度
        public const string Set_Jerk = "DB3.DBX33.1";//急停

        public const string Set_GoReadyPosition = "DB16.DBX1.6";
        public const string Set_GoReceivePosition1 = "DB16.DBX2.0";
        public const string Set_GoSendPosition1 = "DB16.DBX2.2";
        public const string Set_GoAvoidPosition1 = "DB16.DBX2.4";
        public const string Set_GoSendPosition2 = "DB16.DBX2.6";
        public const string Set_GoAvoidPosition2 = "DB16.DBX3.0";
        #endregion
    }
    public class ZJack
    {
        public static List<DataItem> ZJackInfo = new List<DataItem>()
    {
        DataItem.FromAddress("DB3.DBX128.0"),
        DataItem.FromAddress("DB3.DBX150.0"),
        DataItem.FromAddress("DB3.DBX150.1"),
        DataItem.FromAddress("DB3.DBX150.2"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=152 },
        DataItem.FromAddress("DB3.DBX156.0"),
        DataItem.FromAddress("DB3.DBX156.1"),
        DataItem.FromAddress("DB3.DBX172.6"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Word,DB=3,StartByteAdr=158 },
        DataItem.FromAddress("I1.0"),
        DataItem.FromAddress("I0.1"),
        DataItem.FromAddress("I0.2"),
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=3,StartByteAdr=168 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=18 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=8,StartByteAdr=20 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Int,DB=19,StartByteAdr=12 },
    };
        public static List<DataItem> ZJackParams = new List<DataItem>()
    {
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=338 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=330 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=334 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=358 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=362 },
        new DataItem(){DataType=DataType.DataBlock,VarType=VarType.Real,DB=19,StartByteAdr=278 },
        //DataItem.FromAddress("DB3.DBD242"),
        //DataItem.FromAddress("DB3.DBD246"),
        //DataItem.FromAddress("DB3.DBD138"),
    };
        #region Z顶升步进
        //读
        public const string Get_Enable = "DB3.DBX128.0";//使能
        public const string Get_Ready = "DB3.DBX150.0";//顶升伺服就绪
        public const string Get_Alarm = "DB3.DBX150.1";//故障
        public const string Get_LocationFinish = "DB3.DBX150.2";//定位完成
        public const string Get_CurrentPosition = "DB3.DBR152";//当前位置
        public const string Get_HomeFinish = "DB3.DB156.0";//原点完成
        public const string Get_Operating = "DB3.DBX156.1";//运行中
        public const string Get_JogStatus = "DB3.DBX172.6";//Jog状态反馈
        public const string Get_AlarmID = "DB3.DBW158";//故障ID
        public const string Get_HomeSensorStatus = "I1.0";//原点位
        public const string Get_UpperSensorStatus = "I0.1";//上极限位
        public const string Get_LowerSensorStatus = "I0.2";//下极限位
        public const string Get_CurrentSpeed = "DB3.DBR168";//速度
        public const string Get_AutoStep = "DB8.DBI18";
        public const string Get_PauseStep = "DB8.DBI20";
        public const string Get_WaferPos = "DB19.DBI12";//晶圆位置

        //写
        public const string Set_Enable = "DB3.DBX128.0";//使能
        public const string Set_BackHome = "DB3.DBX128.3";//回原点
        public const string Set_LocationStart = "DB3.DBX128.6";//定位启动
        public const string Set_AlarmClear = "DB3.DBX129.0";//故障复位
        public const string Set_Speed = "DB3.DBR130";//速度设定
        public const string Set_Position = "DB3.DBD138";//位置设定
        public const string Set_InitSpeed = "DB19.DBD278";//初始速度
        public const string Set_TopPosition = "DB19.DBD330";//上位
        public const string Set_BottomPosition = "DB19.DBD334";//下位
        public const string Set_UpSpeed = "DB19.DBD358";//上行速度
        public const string Set_DownSpeed = "DB19.DBD362";//下行速度
        public const string Set_Forward = "DB3.DBX128.1";//正转
        public const string Set_Reversal = "DB3.DBX128.2";//反转
        public const string Set_Jerk = "DB3.DBX129.1";//急停

        public const string Set_GoTopPosition = "DB16.DBX4.0";
        public const string Set_GoBottomPosition = "DB16.DBX4.2";
        #endregion
    }

    public interface IPLCService
    {
        Task SetAlarmStatus(int num, CancellationToken tok = default);

        Task SetOnLineStatus(int num, CancellationToken tok = default);

        Task SetBuzzerOFF(CancellationToken tok = default);

        Task<bool> Connect();

        async Task<int> TrackWafers()
        {
            var Jw = Convert.ToInt16(await GetPLCStatus(Jacking.Get_WaferPos).ConfigureAwait(false));
            var Js1 = Convert.ToInt16(await GetPLCStatus(Spin.Get_WaferPos1).ConfigureAwait(false));
            var Js2 = Convert.ToInt16(await GetPLCStatus(Spin.Get_WaferPos2).ConfigureAwait(false));
            var Zw = Convert.ToInt16(await GetPLCStatus(ZJack.Get_WaferPos).ConfigureAwait(false));
            return (Jw << 6) + (Js1 << 4) + (Js2 << 2) + Zw;
        }

        async Task<bool> IsAutoMode()
        {
            List<DataItem> requests = [
                DataItem.FromAddress("DB8.DBX36.2"),
            DataItem.FromAddress("DB8.DBX36.4")
            ];
            var result = await ReadPLCValue(requests).ConfigureAwait(false);
            return (bool?)result[0].Value == true && (bool?)result[1].Value == false;
        }

        /// <summary>
        /// 腔体内是否存在Wafer
        /// </summary>
        /// <returns></returns>
        Task<bool> ExistWafer();

        /// <summary>
        /// 双片模式开关
        /// </summary>
        /// <param name="dualChipMode">true:打开双片模式，false:关闭双片模式</param>
        /// <param name="tok"></param>
        /// <returns>-1:模式切换失败，0：机器内部有晶圆，1：模式切换成功</returns>
        Task<int> SetDualChipMode(bool dualChipMode, CancellationToken tok = default);

        /// <summary>
        /// 获取当前传片模式
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> GetChipMode(CancellationToken tok = default);

        /// <summary>
        /// 双片模式最后一片wafer信号,用于排除最后一片晶圆
        /// </summary>
        /// <param name="lastWafer"></param>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetLastWafer(bool lastWafer, CancellationToken tok = default);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tok"></param>
        /// <returns>true:wafer  false:no wafer</returns>
        Task<bool> OpenLoadLockDoor(CancellationToken tok = default);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task CloseEFEMDoor(CancellationToken tok = default);

        /// <summary>
        /// 放晶圆开始时
        /// </summary>
        /// <returns></returns>
        Task PutWaferStart(CancellationToken tok = default);
        Task PutWaferRequest(CancellationToken tok = default);
        /// <summary>
        /// 放晶圆结束时
        /// </summary>
        /// <returns></returns>
        Task PutWaferEnd(CancellationToken tok = default);
        /// <summary>
        /// 取晶圆开始时
        /// </summary>
        /// <returns></returns>
        Task GetWaferStart(CancellationToken tok = default);
        /// <summary>
        /// 取晶圆结束时
        /// </summary>
        /// <returns></returns>
        Task GetWaferEnd(CancellationToken tok = default);

        /// <summary>
        /// 放晶圆过程中可以吸附
        /// </summary>
        Task WaferCanAdsorption(CancellationToken tok = default);

        ///// <summary>
        ///// 晶圆在预吸附位置吸附完成
        ///// </summary>
        ///// <param name="tok"></param>
        ///// <returns></returns>
        //Task WaferAdsorptionHalf(CancellationToken tok = default);

        Task GetTwisTorrOpenRequest(CancellationToken tok = default);

        Task SetStartVacuum(CancellationToken tok = default);

        Task<bool> Connect(CancellationToken tok = default);



        /// <summary>
        /// 获取PLC状态
        /// </summary>
        Task<object> GetPLCStatus(string plcaddress, CancellationToken tok = default);

        /// <summary>
        /// 批量读取PLC数据
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        Task<List<DataItem>> ReadPLCValue(List<DataItem> list, CancellationToken tok = default);

        /// <summary>
        /// 获取报警信息
        /// </summary>
        Task<object> GetAlarm(CancellationToken tok = default);

        /// <summary>
        /// 设置PLC状态
        /// </summary>
        Task SetPLCStatus(string plcaddress, string value, CancellationToken tok = default);
        Task SetPLCStatus(string address, Int16 value, CancellationToken tok = default);
        string GetAddress();

        /// <summary>
        /// 获取当前光阑孔
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<Int16> GetApertureNumber(CancellationToken tok = default);

        /// <summary>
        /// Aperture移动到指定光阑孔
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task SetApertureMoveTo(Int16 number, CancellationToken tok = default);

        Task SetAperturePosition(double x, double y, CancellationToken tok = default);

        Task SetApertureMove(int num, double pos, CancellationToken tok = default);

        /// <summary>
        /// 手动模式下，允许EFEM从LL取晶圆
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> CanGetFromLL(CancellationToken tok = default);

        /// <summary>
        /// 手动模式下，允许EFEM放晶圆到LL
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task<bool> CanPutToLL(CancellationToken tok = default);

        /// <summary>
        /// 获取真空读数
        /// </summary>
        /// <param name="tok"></param>
        /// <returns>返回多个位置真空度，[0]:前级管道真空度，[1]：上载腔真空度</returns>
        Task<double[]> GetVacuumValue(CancellationToken tok = default);

        /// <summary>
        /// PLC初始化
        /// </summary>
        /// <param name="tok"></param>
        /// <returns>-1初始化失败,0:初始化条件不满足，1:初始化完成</returns>
        Task<int> Initialize(CancellationToken tok = default);

        /// <summary>
        /// PLC自动模式
        /// </summary>
        /// <param name="tok"></param>
        /// <returns></returns>
        Task AutoMode(CancellationToken tok = default);

        Task SetWaferDetectionFinished(CancellationToken tok = default);

    }

    public class WaferStatus
    {
        public static List<DataItem> WaferStatusInfo = new List<DataItem>()
    {
        DataItem.FromAddress("DB11.DBX0.1"),
        DataItem.FromAddress("DB11.DBX0.2"),
        DataItem.FromAddress("DB11.DBX10.2"),
        DataItem.FromAddress("DB11.DBX10.3"),
        DataItem.FromAddress("DB11.DBX10.4"),
        DataItem.FromAddress("DB11.DBX10.5"),
        DataItem.FromAddress("DB11.DBX10.6"),
        DataItem.FromAddress("DB11.DBX10.7"),
        DataItem.FromAddress("DB11.DBX11.0"),
        DataItem.FromAddress("DB11.DBX11.1"),
        DataItem.FromAddress("DB11.DBX11.2"),
    };

        #region 晶圆交互状态

        //安全位，EFEM回到安全位置设True
        public const string Set_SafetyPosition = "DB11.DBX0.0";

        //上料
        public const string Get_JackingReady = "I2.0";
        public const string Get_ValveReady = "I4.4";
        public const string Get_WaferGetFormLL = "DB11.DBX0.1";
        public const string Get_WaferPutToLL = "DB11.DBX0.2";
        public const string Get_WaferPutToStageFinished = "DB11.DBX10.4";

        //下料，检测完成信号
        public const string Set_WaferDetectionFinished = "DB11.DBX10.3";

        public const string Get_WaferPutToLLFinished = "DB11.DBX10.2";
        public const string Get_WaferPutToZStageFinished = "DB11.DBX10.3";

        //可以吸附信号
        public const string Get_WaferCanAdsortption = "DB11.DBX10.6";

        public const string Get_WaferDeChuck = "DB11.DBX11.2";

        public const string Set_EchuckAdsorptionActionFinish = "DB11.DBX10.7";
        //Motion是否在原点
        public const string Set_StageInLoadingPos = "DB11.DBX11.0";

        public const string Get_IsSingleMode = "DB11.DBX10.5";

        #endregion
    }

    public class SubstrateTrackingResult
    {
        public string LastEventId { get; init; } = "";

        public List<Foup> Foups { get; init; } = [];

        public List<StrayWafer> StrayWafers { get; init; } = [];
    }

    public class Foup
    {
        public WaferState[] Slots { get; init; } = [];

        public bool IsOpen { get; init; }

        public bool Placement { get; init; }
    }

    public class StrayWafer
    {
        public WaferLocation Location { get; init; }

        public int Foup { get; init; }

        public int Slot { get; init; }
    }

    public static class Key
    {
        public const string SubstrateTrackingStream = "substrate_tracking_stream";
    }

    public record class StageHVReponse
    {
        public MPDStatus Bv2 { get; set; } = new MPDStatus();

        public MPDStatus Bv3 { get; set; } = new MPDStatus();

        public MPDStatus Hv3 { get; set; } = new MPDStatus();

        public bool IsInterLock { get; set; }

        public bool SensorData { get; set; }

        public bool SensorError { get; set; }

        public bool HVONseq { get; set; }

        public bool HVONFinish { get; set; }

        public bool HVOFFseq { get; set; }

        public bool HVOFFFinish { get; set; }

        public bool IsTracking { get; set; }

        public bool IsFault { get; set; }
    }

    public record class MPDStatus
    {
        public bool IsConnect { get; set; }

        public bool IsEnable { get; set; }

        public bool IsFault { get; set; }

        public bool IsOverVoltage { get; set; }

        public bool IsOverCurrent { get; set; }

        public bool IsOverTemperature { get; set; }

        public bool SupplyRail { get; set; }

        public bool HardwareEnable { get; set; }

        public bool SoftwareEnable { get; set; }

        public ushort MonitorVoltage { get; set; }

        public ushort MonitorCurrent { get; set; }

        public ushort TargetVoltage { get; set; }

        public ushort TargetCurrent { get; set; }

        public ushort SetValue { get; set; }
    }

    public class StageHVRequest
    {
        public ushort BV2 { get; set; }
        public ushort BV3 { get; set; }
    }

    public class GunHVReponse
    {
        public bool Interlock { get; set; }
        public bool Warning { get; set; }
        public bool Fault { get; set; }
        public required GunPowerStatus Beam { get; set; }
        public required GunPowerStatus Filament { get; set; }
        public required GunPowerStatus Extractor { get; set; }
        public required GunPowerStatus Suppressor { get; set; }
    }

    public class OutputStatus
    {
        public bool Enable { get; set; }
        public bool ON { get; set; }
        public bool Ramp { get; set; }
        public bool Wobble { get; set; }
        public bool FrequencyLock { get; set; }
        public bool Warning { get; set; }
        public bool Fault { get; set; }
    }

    public class OutputError
    {
        public bool InterLock { get; set; }
        public bool SupplyFault { get; set; }
        public bool Internal { get; set; }
        public bool Temperature { get; set; }
        public bool OverCurrent { get; set; }
        public bool OverVoltage { get; set; }
    }


    public class GunPowerStatus
    {
        public required OutputStatus OutputStatus { get; set; }
        public required OutputError OutputError { get; set; }
        public string ErrorInfo
        {
            get
            {
                if (OutputError.InterLock) return "InterLock";
                else if (OutputError.Temperature) return "OverTemperature";
                else if (OutputError.SupplyFault) return "SupplyFault";
                else if (OutputError.Internal) return "SoftwareError";
                else if (OutputError.OverCurrent) return "OverCurrent";
                else if (OutputError.OverVoltage) return "OverVoltage";
                else return "";
            }
        }
        public double SlewRate { get; set; }
        public double MonitorVoltage { get; set; }
        public double TargetVoltage { get; set; }
        public double MonitorCurrent { get; set; }
        public double TargetCurrent { get; set; }
        public double ActualDemand { get; set; }
    }

    public interface IHVServiceClient
    {
        [Get("/StageHV/GetStatus")]
        Task<StageHVReponse> GetStageHVStatus();

        [Post("/StageHV/ONStart")]
        Task StageHVStartON();

        [Post("/StageHV/ONFull")]
        Task StageHVON();

        [Post("/StageHV/OFF")]
        Task StageHVOFF();

        [Post("/StageHV/SetOutVoltage")]
        Task SetStageHV(StageHVRequest request);


        [Get("/GunHV/GetStatus")]
        Task<GunHVReponse> GetGunHVStatus();

        [Post("/GunHV/ClearFault")]
        Task GunHVClearFault(CancellationToken tok = default);

        [Post("/GunHV/SetBeamPower/{value}")]
        Task GunHVSetBeamPower(bool value, CancellationToken tok = default);

        [Post("/GunHV/SetBeamOutput/{value}")]
        Task GunHVSetBeamOutput(double value, CancellationToken tok = default);

        [Post("/GunHV/SetBeamSlewRate/{value}")]
        Task GunHVSetBeamSlewRate(double value, CancellationToken tok = default);

        [Post("/GunHV/SetFilamentPower/{value}")]
        Task GunHVSetFilamentPower(bool value, CancellationToken tok = default);

        [Post("/GunHV/SetFilamentOutput/{value}")]
        Task GunHVSetFilamentOutput(double value, CancellationToken tok = default);

        [Post("/GunHV/SetFilamentSlewRate/{value}")]
        Task GunHVSetFilamentSlewRate(double value, CancellationToken tok = default);

        [Post("/GunHV/SetExtractorPower/{value}")]
        Task GunHVSetExtractorPower(bool value, CancellationToken tok = default);

        [Post("/GunHV/SetExtractorOutput/{value}")]
        Task GunHVSetExtractorOutput(double value, CancellationToken tok = default);

        [Post("/GunHV/SetExtractorSlewRate/{value}")]
        Task GunHVSetExtractorSlewRate(double value, CancellationToken tok = default);

        [Post("/GunHV/SetSuppressorPower/{value}")]
        Task GunHVSetSuppressorPower(bool value, CancellationToken tok = default);

        [Post("/GunHV/SetSuppressorOutput/{value}")]
        Task GunHVSetSuppressorOutput(double value, CancellationToken tok = default);

        [Post("/GunHV/SetSuppressorSlewRate/{value}")]
        Task GunHVSetSuppressorSlewRate(double value, CancellationToken tok = default);
    }


    public interface IEChuckServiceClient
    {
        [Post("/ChuckWafer")]
        Task ChuckWafer();

        [Post("/PutWaferValue")]
        Task PutWaferValue();

        [Post("/SetAdsorptionVoltage/{Value}")]
        Task SetAdsorptionVol(Int16 value);

        [Post("/SetReleaseVoltage/{Value}")]
        Task SetReleaseVol(Int16 value);

        [Post("/SetPunctureVoltage/{Value}")]
        Task SetPunctureVol(UInt16 value);

        [Post("/SetPunctureFrequency/{Value}")]
        Task SetPunctureFrequency(UInt16 value);

        [Post("/SetPunctureDutyRatio/{Value}")]
        Task SetPunctureDutyRatio(UInt16 value);

        [Post("/SetPunctureTime/{Value}")]
        Task SetPunctureTime(UInt16 value);

        [Post("/AdsorptionAction")]
        Task AdsorptionAction();

        [Post("/AdsorptionCheck")]
        Task AdsorptionCheck();

        [Post("/ReleaseAction")]
        Task ReleaseAction();

        [Post("/PunctureAction")]
        Task PunctureAction();

        [Post("/JerkAction")]
        Task JerkAction();

        [Get("/GetAdsorptionVoltage")]
        Task<Int16> GetAdsorptionVol();

        [Get("/GetReleaseVoltage")]
        Task<Int16> GetReleaseVol();

        [Get("/GetPunctureVoltage")]
        Task<UInt16> GetPunctureVol();

        [Get("/GetPunctureFrequency")]
        Task<UInt16> GetPunctureFrequency();

        [Get("/GetPunctureDutyRatio")]
        Task<UInt16> GetPunctureDutyRatio();

        [Get("/GetPunctureTime")]
        Task<UInt16> GetPunctureTime();

        [Get("/GetCapacitanceValue")]
        Task<double> GetCapaciTance();

        [Get("/GetPunctureValue")]
        Task<double> GetPuncture();
    }


    public class AsyncTimeout
    {
        readonly CancellationTokenSource cts = new();

        public async Task Execute(TimeSpan time, Func<CancellationToken, Task> func)
        {
            try
            {
                cts.Token.ThrowIfCancellationRequested();
                cts.CancelAfter(time);
                await func(cts.Token).ConfigureAwait(false);
            }
            finally
            {
                cts.TryReset();
            }
        }

        public async Task<T> Execute<T>(TimeSpan time, Func<CancellationToken, Task<T>> func)
        {
            try
            {
                cts.Token.ThrowIfCancellationRequested();
                cts.CancelAfter(time);
                return await func(cts.Token).ConfigureAwait(false);
            }
            finally
            {
                cts.TryReset();
            }
        }

        public static Task<T> Run<T>(TimeSpan time, Func<CancellationToken, Task<T>> func)
        {
            var timeout = new AsyncTimeout();
            return timeout.Execute(time, func);
        }

        public static Task Run(TimeSpan time, Func<CancellationToken, Task> func)
        {
            var timeout = new AsyncTimeout();
            return timeout.Execute(time, func);
        }
    }

    public record class WaferTransferRequest(int Foup,
    int Slot,
    int Arm,
    bool UseEChuck,
    bool UseXYStage);

    public record class WaferLoadingQueueRequest(int Foup,
    List<int> Slots,
    bool UseEChuck,
    bool UseXYStage);
}
